到了30天的中點啦!今天要介紹的是第11條守則,看來這個月結束之後可以紀錄到22條守則左右,繼續加油吧!
今天的守則跟昨天一樣,著墨於assignment operator的部分,這個守則是:
Handle assignment to self in operator=
說明的是在assignment相關操作中,需要注意到的一點是我們有時候會把objectassign 給它自己。
最明顯的操作就像是這樣:
class Widget {...};
Widget w;
...
w = w;
第一反應可能是,誰會這樣寫~沒有意義!但有時候assign給自己的操作是比較隱晦一點的,例如像這樣:
a[i] = a[j]; // when i == j, assignment to itself
*px = *py; // if px and py point to the same thing, assignment to itself
是不是就蠻容易遇到的!
一般而言,我們在對於同樣類型的多個物件做操作的時候,就應該考量到它們其實同一物件的情形,甚至是不同物件類型,例如base class與derived class雖是不同類型,但它們仍可能是存放或指向同一物件!
那這時要注意什麼呢?考慮以下物件:
class Bitmap {...};
class Widget
{
private:
Bitmap *pb;
}
以下是看似合理,但當指派給自己的時候會有問題的寫法:
Widget& Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
如果此時指派給自己,第一行pb
先刪掉了,最後指派給自己,預期不會變的操作,竟然造成自己去指向一個被刪除的物件!
而要避免此情況的傳統方法就是在operator=
的一開始採用 identity test ,
先檢查是不是指派給自己的操作:
Widget& Widget::operator=(const Widget& rhs)
{
if(this == &rhs) return *this;
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
這樣就可以避免掉self-assignment-unsafe的情形~
除了identity test,還有別的作法,我們明日繼續看下去~